home *** CD-ROM | disk | FTP | other *** search
- /* dialogQuake INIT.c 5 June 89
- *
- * written by Mike Scanlin
- * inspiration by Andy Jeffrey
- * unwilling testing by "Goobs" Galvan
- *
- * INIT that installs a patch on _ModalDialog that will,
- * when _ModalDialog is called, install a tail patch on
- * _GetNextEvent that causes the frontmost window to move
- * around a bit (making it hard to click on items with any
- * real accuracy). The patch to _GetNextEvent is removed
- * before _ModalDialog returns and the patch to _ModalDialog
- * can be removed by typing cmd-option-shift-tab while a
- * modal dialog is frontmost.
- */
-
- /* traps we patch */
- #define ModalDialog 0xA991
- #define GetNextEvent 0xA970
-
- /* uses a bit of self-modifying code */
- #define JMP 0x4EF9
-
- #define TAB_KEY 0x09
- #define memFullErr -108
-
- void main(void);
-
- void main()
- {
- asm {
-
- /* the next 20 or so lines are the only ones that get
- * executed during installation. They get some space in
- * the system heap for the patches and then patch
- * _ModalDialog. */
-
- /* save register */
- move.l D4,-(SP)
-
- /* get the old trap address */
- move #ModalDialog,D0
- _GetTrapAddress
-
- /* set the address for the JMP instruction that calls
- * the original trap */
- lea @origMD,A1
- move.l A0,(A1)
-
- /* get some space in the system heap for our patches
- * (note that this space is for both patches) */
- lea @last,A0
- lea @modalDialogPatch,A1
- suba.l A1,A0
- move.l A0,D0
- move.l D0,D4
- _NewPtr SYS
-
- /* if there's not enough memory then abort the
- * installation */
- cmpi #memFullErr,D0
- beq.s @noPatch
-
- /* save address for _BlockMove */
- move.l A0,-(SP)
-
- /* set the trap address to the space we just got */
- move #ModalDialog,D0
- _SetTrapAddress
-
- /* now move our patch into place */
- lea @modalDialogPatch,A0
- move.l (SP)+,A1
- move.l D4,D0
- _BlockMove
-
- @noPatch
-
- /* restore register and exit installation code */
- move.l (SP)+,D4
- rts
-
- /********************************************
- * Here's the new _ModalDialog. It first installs
- * a tail patch on _GetNextEvent and then calls
- * the existing _ModalDialog. On exit this patch
- * will unpatch the _GetNextEvent patch.
- *******************************************/
-
- @modalDialogPatch
-
- /* save the original _GetNextEvent address */
- move #GetNextEvent,D0
- _GetTrapAddress
-
- /* set the address for the JMP instruction that calls
- * the original trap */
- lea @origGNE,A1
- move.l A0,(A1)
-
- /* patch _GetNextEvent */
- lea @getNextEventPatch,A0
- move #GetNextEvent,D0
- _SetTrapAddress
-
- /* pop the original return address and save it */
- lea @exitMD,A0
- move.l (SP)+,(A0)
-
- /* set the return address to our patch */
- pea @tailMDPatch
-
- /* the nops get filled with the address of the original
- * _ModalDialog */
- dc JMP
- @origMD nop
- nop
-
- /* _ModalDialog returns here */
-
- @tailMDPatch
-
- /* remove the patch to _GetNextEvent */
- lea @origGNE,A0
- move.l (A0),A0
- move #GetNextEvent,D0
- _SetTrapAddress
-
- /* return to the place that called _ModalDialog */
- dc JMP
- @exitMD nop
- nop
-
-
- /********************************************
- * Here's the new _GetNextEvent. If a random
- * amount of time has passed then call
- * _MoveWindow to move the frontmost window
- * (a modal dialog) in a random direction.
- *******************************************/
-
- @getNextEventPatch
-
- /* pop the original return address and save it */
- lea @exitGNE,A0
- move.l (SP)+,(A0)
-
- /* save pointer to the event record so we can get to
- * it when the real _GetNextEvent returns */
- lea @eventRecPtr,A0
- move.l (SP),(A0)
-
- /* set the return address to our patch */
- pea @tailGNEPatch
-
- /* the nops get filled with the address of the original
- * _GetNextEvent */
- dc JMP
- @origGNE nop
- nop
-
- /* _GetNextEvent returns here */
-
- @tailGNEPatch
-
- /* save registers */
- movem.l D0-D2/A0-A2,-(SP)
-
- /* if they don't want us around, then exit */
- lea @noMoreHassle,A0
- tst (A0)
- bne @goodBye
-
- /* check if the event is a keyDown event */
- lea @eventRecPtr,A0
- move.l (A0),A0
- move OFFSET(EventRecord,what)(A0),D0
- cmpi #keyDown,D0
- bne.s @noKeyDown
-
- /* it's a keydown, but is it the special remove-us key? */
- move.l OFFSET(EventRecord,message)(A0),D0
- cmpi.b #TAB_KEY,D0
- bne.s @noKeyDown
- move OFFSET(EventRecord,modifiers)(A0),D0
- andi #cmdKey + optionKey + shiftKey,D0
- eori #cmdKey + optionKey + shiftKey,D0
- bne.s @noKeyDown
-
- /* they don't like us any more so remove ourself. First beep
- * to let them know that we got the message to go away */
- move #1,-(SP)
- _SysBeep
-
- /* set a flag so we know not to bother the nice user any more */
- lea @noMoreHassle,A0
- move #1,(A0)
-
- /* move the frontmost window to a nice place in case it was
- * partially moved off the screen by _MoveWindow */
- move.l WindowList,-(SP)
- move #30,-(SP)
- move #30,-(SP)
- bra.s @moveToUpperLeft
-
- @noKeyDown
-
- /* has the timer expired? */
- lea @timer,A0
- subi #1,(A0)
- bpl.s @goodBye
-
- /* reset the timer to wait a random amount of time before
- * expiring again */
- subq #2,SP
- _Random
- move (SP)+,D0
-
- /* note: make the 0x3F smaller to move the window more often */
- andi #0x3F,D0
- lea @timer,A0
- move D0,(A0)
-
- /* push a WindowPtr for _MoveWindow. Note: this does not
- * check for Ghost Windows */
- move.l WindowList,A2
- move.l A2,-(SP)
-
- /* get a couple of random numbers in the range [-7..+7] */
- subq #2,SP
- _Random
- move (SP)+,D1
- move D1,D2
- asr #8,D1
- andi #0x8007,D1
- bpl.s @2
- bclr #15,D1
- neg D1
- @2 ext D2
- andi #0x8007,D2
- bpl.s @3
- bclr #15,D2
- neg D2
- @3
-
- /* push a random h coordinate */
- move OFFSET(GrafPort,portBits)+OFFSET(BitMap,bounds)+OFFSET(Rect,left)(A2),D0
- neg D0
- add D1,D0
- move D0,-(SP)
-
- /* push a random v coordinate */
- move OFFSET(GrafPort,portBits)+OFFSET(BitMap,bounds)+OFFSET(Rect,top)(A2),D0
- neg D0
- add D2,D0
- move D0,-(SP)
-
- @moveToUpperLeft
- sf -(SP)
- _MoveWindow
-
- @goodBye
-
- /* restore registers */
- movem.l (SP)+,D0-D2/A0-A2
-
- /* return to _ModalDialog */
- dc JMP
- @exitGNE nop
- nop
-
- /* variables */
- @noMoreHassle dc 0
- @eventRecPtr dc.l 0
- @timer dc 0
-
- @last
- }
- }
-